﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WordNet.Core.ElementContracts;
using WordNet.Core.Extensions;

namespace WordNet.Core
{
    public class WordID:IWordID
    {

        public const String wordIDPrefix = "WID-";
        public const String unknownLemma = "?";
        public const String unknownWordNumber = "??";

        private readonly ISynsetID _id;
        private readonly String _lemma;
        private readonly int _num;

        public WordID(int offset, POS pos, int num)
            : this(new SynsetID(offset, pos), num)
        {

        }
        public WordID(int offset, POS pos, String lemma)
            : this(new SynsetID(offset, pos), lemma)
        {

        }
        public WordID(ISynsetID id, int num)
        {
            if (id == null)
                throw new ArgumentNullException();
            num.CheckWordNumber();
            _id = id;
            _num = num;
            _lemma = null;
        }

        public WordID(ISynsetID id, String lemma)
        {
            if (id == null)
                throw new ArgumentNullException();
            if (lemma.Trim().Length == 0)
                throw new ArgumentOutOfRangeException();
            _id = id;
            _num = -1;
            _lemma = lemma.ToLower();
        }

        public WordID(ISynsetID id, int num, String lemma)
        {
            if (id == null)
                throw new ArgumentNullException();
            if (lemma.Trim().Length == 0)
                throw new ArgumentException();
            num.CheckWordNumber();
            _id = id;
            _num = num;
            _lemma = lemma;
        }
        public ISynsetID SynsetID
        {
            get { return _id; }
        }

        public int WordNumber
        {
            get
            {
                return _num;
            }
        }

        public string Lemma
        {
            get { return _lemma; }
        }

        public POS PartOfSpeech
        {
            get { return _id.PartOfSpeech; }
        }

        public override int GetHashCode()
        {
            return 31 * _id.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            if (Object.ReferenceEquals(obj, null))
                return false;
            if (Object.ReferenceEquals(this, obj))
                return true;
            IWordID other = obj as IWordID;
            if (other == null)
                return false;
           
           if (!_id.Equals(other.SynsetID))
                return false;
            if (other.WordNumber != -1 && _num != -1 && other.WordNumber != _num)
                return false;
            if (other.Lemma != null && _lemma != null)
                if (!other.Lemma.Equals(_lemma, StringComparison.OrdinalIgnoreCase))
                    return false;
            return true;
        }

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(wordIDPrefix);
            sb.Append(_id.Offset.ZeroFillOffset());
            sb.Append('-');
            sb.Append(Char.ToUpper(_id.PartOfSpeech.Tag));
            sb.Append('-');
            sb.Append((_num < 0) ? unknownWordNumber : _num.ZeroFillWordNumber());
            sb.Append('-');
            sb.Append((_lemma == null) ? unknownLemma : _lemma);
            return sb.ToString();
        }

        public static IWordID parseWordID(String value)
        {
            if (value == null)
                throw new ArgumentNullException();
            if (value.Length < 19)
                throw new ArgumentNullException();
            if (!value.StartsWith("WID-"))
                throw new ArgumentNullException();

            // get synset id
            int offset = int.Parse(value.Substring(4, 12));
            POS pos = POS.GetPartOfSpeech(value[13]);
            ISynsetID id = new SynsetID(offset, pos);

            // get word number
            String numStr = value.Substring(15, 17);
            if (!numStr.Equals(unknownWordNumber))
            {
                int num = int.Parse(numStr);
                return new WordID(id, num);
            }

            // get lemma
            String lemma = value.Substring(18);
            if (lemma.Equals(unknownLemma) || lemma.Length == 0)
                throw new ArgumentException();

            return new WordID(id, lemma);
        }
    }
}
